/**
 * ex9. 接口
 *
 * @author cyy
 * @date 2020/11/9
 */
package main

import (
	"fmt"
)

// 接口
type Usber interface {
	charge()
	transport()
	InnerInterface
}

type InnerInterface interface {
	fix()
}

type Phone struct {
	Name string
}

func (p *Phone) start() {
	fmt.Println(p.Name, "开机")
}

func (p *Phone) stop() {
	fmt.Println(p.Name, "关机")
}

func (p *Phone) transport() {
	fmt.Println(p.Name, "传输")
}

func (p *Phone) charge() {
	fmt.Println(p.Name, "充电")
}

func (p *Phone) fix() {
	fmt.Println(p.Name, "修理")
}

type Camera struct {
	Name string
}

func (c Camera) charge() {
	fmt.Println(c.Name, "充电")
}

func (c Camera) transport() {
	fmt.Println(c.Name, "传输")
}

func (c Camera) fix() {
	fmt.Println(c.Name, "修理")
}

/*
	空接口
		没有任何约束，任何类型变量都可以实现空接口
		类似java中的Object
*/
type Object interface{}

func show(o interface{}) {
	fmt.Printf("值：%v，类型：%T\n", o, o) // 1 int
}

type Usber2 interface {
}

func main() {
	p := &Phone{Name: "OPPO"}
	p.start()
	// 接口嵌套
	p.fix()

	// usb实例化
	var u = Usber(&Phone{Name: "OPPO"})
	u.charge()

	/*
		结构体「值接收者」和「指针接收者」实现接口的区别
			结构体【值类型接收者】实现接口
				值类型实例 和 指针类型实例 都可以赋值给值类型接收者的接口类型变量
				如果结构体中的方法是值接收者，那么实例化后的结构体值类型和结构体指针类型都可以赋值给接口变量
			结构体【指针类型接收者】实现接口
				只能将实例化后的 结构体指针类型 赋值给接口变量
				如果结构体中的方法是指针接收者，那么实例化后结构体指针类型都可以赋值给接口变量，结构体值类型没法赋值给接口变量
	*/
	var u1 Usber = &Phone{Name: "VIVO"}
	var u2 Usber = Camera{Name: "Casio"}
	var u3 Usber = &Camera{Name: "Sony"}
	u1.charge()
	u2.charge()
	u3.charge()

	var o Object // 等同于 var o interface{}
	a := 1
	o = a
	fmt.Printf("值：%v，类型：%T\n", o, o) // 1 int

	show(1)    // 值：1，类型：int
	show("1")  // 值：1，类型：string
	show(1.1)  // 值：1.1，类型：float64
	show(true) // 值：true，类型：bool

	/*
		类型断言 —— 可用于判断空接口中值的类型
			格式：x.(T) —— 源数据.(目标类型)
			返回转化后的变量和一个布尔值
	*/
	var b interface{}
	b = "你好，golang"
	v, ok := b.(string)
	if ok {
		fmt.Println("a是一个string类型的值 ——", v)
	} else {
		fmt.Println("a不是一个string类型的值")
	}

	judgeType(1)
	judgeType("string")
	judgeType(1.1)

	// 多接口实现
	var _ Usber = p
	var _ Usber2 = p
	p.start()
	p.stop()
	p.charge()

	userinfo := make(map[string]interface{})
	userinfo["name"] = "张三"
	userinfo["age"] = 22
	userinfo["hobby"] = []string{"吃饭", "睡觉", "打豆豆"}
	userinfo["phone"] = Phone{Name: "oppo"}
	fmt.Println(userinfo["name"])
	fmt.Println(userinfo["age"])
	fmt.Println(userinfo["hobby"])

	// 空接口类型不支持索引、自定义类型，可以通过类型断言转换
	// 	fmt.Println(userinfo["hobby"][1]) 	✖	type interface {} does not support indexing
	// 	fmt.Println(userinfo["phone"].Name)	✖	type interface {} is interface with no methods
	fmt.Println(userinfo["hobby"].([]string)[0])
	fmt.Println(userinfo["phone"].(Phone).Name)

}

// 空接口作为函数参数
func judgeType(o interface{}) {
	// .(type) 用于判断一个变量的类型， 只能结合switch语句使用
	switch /* v := */ o.(type) {
	case int:
		fmt.Println("o is a int")
	case string:
		fmt.Println("o is a string")
	case bool:
		fmt.Println("o is a bool")
	default:
		break
	}
}
